package com.tedu.api.io;

import java.io.IOException;

import org.junit.Test;

import java.io.RandomAccessFile;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * IO流:传输数据
 * File文件类、文件夹类:无法读写数据
 * RandomAccessFile:读写按照字节,读写类不明确,靠构造器传入第二个参数确定
 * <p>
 * Java 提出一套 标准 IO--
 * 方向区别:输入流---(读:针对文件,文件往程序中走，文件"相对于程序")
 * 输出流---(写:针对文件,文件从程序写出写出"相对于程序")
 * 输入流和输出流创建方式???
 * 输入流  InputStream(抽象类)---顶级父类---读操作
 * 输出流  OutputStream(抽象类)---顶级父类---写操作
 * 以上两个流定义所有流具备1读写操作,本身无法实例化
 * 按照功能进行区别:
 * 低级流(专门搬运数据的) 【又叫节点流】
 * FileInputStream 文件输入流:读操作    InputStream(抽象类)
 * FileOutputStream    文件输出流:写操作    OutputStream(抽象类)
 * 功能:建立在程序与数据源之间的"管道",所有数据传输通低级流【节点流】
 * 高级流(不能独立存在的流)  【又叫处理流】
 * 处理低级流的数据,并且可以被其他高级流所处理!
 * 理解:处理搬运数据的流【种类多】
 * -------流:明确功能,创建对象:直接使用低级流--高级流创建
 * 项目:聊天室 Version1 IO流:针对传字符串
 */
public class IOAPI {
    @Test
    public void testIO() throws IOException {
        //创建标准IO流  方向划分  输入流输出流--功能:低级流【节点流】
        //需求:从项目中写出"fox.txt" 低级流:FileOutputStream
        //创建文件输出流  构造器("相对路径+文件全称")
        // FileNotFoundException    无文件异常  路径或者文件名写错
        FileOutputStream fos = new FileOutputStream("fos.txt");
        /**
         * 输出一句话:
         * write(字符串)  返回值:void 空
         * 作用:写出一个文件内容:字节数组
         * Stirng 字符串方法:getBytes()  可以将字符串转换成字符数组 char[]
         */
        fos.write("".getBytes());//叉出去
        //标准IO流必须关闭
        fos.close();//避免内存占用过大

    }

    /**
     * FileOutputStream实现类---构造器使用方法
     * new FileOutputStream(String path,boolean append)  一般用这个
     * 通过第二个参数,确定数据是否追加,默认不追加,true追加,反之不
     * new FileOutputStream(File file,boolean append);
     */
    @Test
    public void testIO追加(){
        //当前 API 项目 下添加 fos.txt文件--增加追加攻击效果
        //相对路径  ./fos.txt 不写./ 直接写文件效果一样 都是当前目录下
        try {
            FileOutputStream fos = new FileOutputStream("fos.txt", true);//叉出去
            String str = "这样也痛吗 全是食言的坏孩子 买了 我买单 骨碌碌 转圈圈 彼岸葬送 离开克拉拉 命令执行 截云~断岳 剑出~山倾 来得正好 就是你了 0分~下一个 负分~给我滚 你再打 不许跑";
            fos.write(str.getBytes());//这个是有大病  必须叉出去
            fos.close();//关掉关掉，通通要关掉
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

    /**
     * 低🐓流
     * 文件输入流 FileInputStream
     * read(字节数组)  返回值:int类型
     * 作用:读取到一个字节的信息
     */
    @Test
    public void testInputStream() {

        try {
            FileInputStream fis = new FileInputStream("fos.txt");//创建文件输入流
            //存10KB  字节数组
            byte[] bytes = new byte[1024 * 100];//以KB进行传
            //不想看到整数值
            int s = fis.read(bytes);//叉出去
            //String字符串类--提供构造器方法  按照字节数组进行输出字符串
            //new String 开始读取，结束读取
            //将【二进制值】整数 转换为 字符串
            String str = new String(bytes, 0, s);
            //一次性将给定的字节数据【10KB】写入到文件中,文件从0开始写入,到-1结束,写入完毕
            System.out.println(str);
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

    @Test
    public void testWork() {
        //1.创建  被复制文件
        try {
            FileInputStream fis = new FileInputStream("71f9736f56021ce87b2e6b40d6cb7945.mp4");
            //创建输出流
            FileOutputStream fos = new FileOutputStream("771f9736f56021ce87b2e6b40d6cb7945.mp4");
            //用于保存读取字节量
            int len = -1;
            //10KB速度进行
            byte[] bytes = new byte[1024 * 10];
            //一直读取，不等于-1，一直读
            long start = System.currentTimeMillis();//测试毫秒数

            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            long end = System.currentTimeMillis();
            System.out.println("测试传输时间:" + (end - start));
            //关掉
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

    /**
     * 高🐓流【处理流】:处理低级流以及其他高级流的一个"种"流
     * 特点:不能独立存在,一定要处理低级流
     * BufferedInputStream---高🐓流:快速读  缓冲输入流
     * BufferedOutputStream---高🐓流:快速写  缓冲输出流
     * 内嵌一套按照实际传输数据大小,随机产生字节数大小
     * 高🐓流内套低级流
     * 语法:BufferedInputStream bis=new BufferedInputStream(低级流引用);
     * 需求 视频 使用 IO 【低🐓+高🐓】--进行快速复制
     */
    @Test
    public void testCVQ() {
        //创建低级输入流
        try {
            FileInputStream fis = new FileInputStream("71f9736f56021ce87b2e6b40d6cb7945.mp4");
            BufferedInputStream bis = new BufferedInputStream(fis);//低级流命名搞里头
            //创建低级输出流
            FileOutputStream fos = new FileOutputStream("871f9736f56021ce87b2e6b40d6cb7945.mp4");
            BufferedOutputStream bos = new BufferedOutputStream(fos);//低级流命名搞里头
            //2.定义整数变量保存每次读取的字节量
            int len = -1;
            //3.把高级流:缓冲输入流--读取的数据--保存交给len--结果不等于-1
            //(len=bis.read())!=-1
            long start = System.currentTimeMillis();
            //read()  读取产生合理的字节
            while ((len = bis.read()) != -1) {//叉出去
                //write() 读取【缓冲字符输出流:自动产生合理字节数据】
                bos.write(len);
            }
            long end = System.currentTimeMillis();
            System.out.println("花费时间" + (end - start));
            //
            if (bos != null)
                try {
                    fis.close();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

    /**
     * BufferedOutputStream 缓冲输出流
     * 需求:写出文件:bos.txt,写出:一段文字
     * IO异常最多, 采取捕获异常并处理
     */
    @Test
    public void testBOS(){
        //创建低级流--写出bos.txt
        try {
            FileOutputStream fos = new FileOutputStream("bos.txt");
            //创建高级流写出一段文本【缓冲区:字节数组】
            BufferedOutputStream bos = new BufferedOutputStream(fos);//上命名加入下
            String str = "阴成啥了";
            //write(byte[] b)  作用:写出字节数组
            bos.write(str.getBytes());//叉出去
            /**str数据量小  缓冲区大  强制送出
             * 45人  车100  晚上9
             * flush()
             * 作用:可以强制将内部缓冲区数据一次性读写
             * 缺点:频繁使用flush降低读写
             */
            //bos.flush();
            if (bos != null)
                //高级跟低级一出现，先关高级后关低级
                try {
                    bos.close();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();}
                } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 标准IO需要和异常互相存在
     * 异常重点:1认识代码中抛出异常【查API】,异常产生原因
     * 2.异常的处理 快捷键 【ctrl+alt+T】
     * 语法try{
     * 怀疑有错误或者已经提示异常的代码,进行包起来
     * }catch(小异常名字 e){
     * e.print();   //打印异常信息---通过异常信息解决问题
     * }catch(中异常名字 e){catch可以抓多个
     * <p>
     * }finally{
     * 一定会执行的代码块
     * }
     *
     * 低级 FileOutputStream 文件输出流---写出
     * 低级 FileInputStream  文件输入流---写入
     * 高级 Buffered0OutputStream  缓冲输出流--写出--功能:缓冲区
     * 高级 BufferedInputStream 缓冲输入流--输入---功能:缓冲区
     *
     * 考试题: final与finally的区别?
     * final关键字:修饰 变量 方法  类-->让变量成常量
     * 方法不可重写   类不能被继承
     * finally关键字:异常处理机制中进行捕获异常
     * 写finally关键字所有异常都不符合，一定会执行语法块
     * 通常使用在IO流中:关闭流为主  关闭高级会间接关闭低级流
     * <p>
     * 需求:BOS高级流---重写结合异常--->标准IO流
     */
    @Test
    public void testBOS1() {
        //先将流进行置空处理--可以进行覆盖且不用多次创建  还可以关闭流
        FileOutputStream fos = null;//低级流--搬运数据
        BufferedOutputStream bos = null;//高级流--处理低级流:缓冲输出流
        //2.捕获异常操作  ctrl+alt+t  抓
        //创建低级流
        try {
            fos = new FileOutputStream("BOS标准写法.txt");
            bos = new BufferedOutputStream(fos);//低级流扔进高级流
            //高级流:缓冲输出流---功能 缓冲区【字节数组】
            bos.write("标准流写法".getBytes());//叉出去
            //缓冲区:数据量比较小---采用flush()  数据一次性写出
            bos.flush();
        } catch (FileNotFoundException e) {//文件不存在异常 路径写错 文件不存在
            e.printStackTrace();//打印异常信息
            System.out.println("小异常:文件不存在");
        } catch (IOException e) {    //IO流最大的异常  小异常不处理?
            e.printStackTrace();
            System.out.println("中异常:IO流异常");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("大异常");
        } finally {
            //一定执行代码块: IO流关闭---高级流关高级,可以顺带关闭低级
            //                     ---低级流,关闭低级流【捕获异常】
            //先判断，高级流--是否是个对象--是否为空【有没有高级流对象】--有则不为空
            //没有高级流对象不必关闭
            if (bos != null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

        }
    }
    }
